package net.oschina.arvin.admin.context;

import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import net.oschina.arvin.admin.web.converter.StringToConverterVOConverter;
import net.oschina.arvin.admin.web.converter.StringToDateConverter;
import net.oschina.arvin.admin.web.message.converter.CustomMappingJackson2HttpMessageConverter;
import org.springframework.boot.autoconfigure.web.HttpMessageConverters;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.convert.ConversionService;
import org.springframework.core.convert.converter.Converter;
import org.springframework.format.support.FormattingConversionServiceFactoryBean;
import org.springframework.http.HttpMethod;
import org.springframework.http.MediaType;
import org.springframework.http.converter.ByteArrayHttpMessageConverter;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder;
import org.springframework.http.converter.xml.MappingJackson2XmlHttpMessageConverter;
import org.springframework.web.bind.support.ConfigurableWebBindingInitializer;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.PathMatchConfigurer;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;

import java.nio.charset.Charset;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;

/**
 * WebMVC 配置
 *
 * @author Arvin
 * @time 2017/11/20 21:37
 */
@Configuration
public class CustomWebMvcConfig extends WebMvcConfigurerAdapter {

    /**
     * 在开发WebAPI的时候，我们基本是需要跨域进行请求， SpringBoot 支持全局的跨域请求配置
     */
    @Override
    public void addCorsMappings(CorsRegistry registry) {
        // 指定为全局开启
        registry.addMapping("/**").allowedOrigins("*")
                .allowedMethods(HttpMethod.GET.name(),
                        HttpMethod.HEAD.name(),
                        HttpMethod.POST.name(),
                        HttpMethod.PUT.name(),
                        HttpMethod.DELETE.name(),
                        HttpMethod.OPTIONS.name())
                .allowCredentials(false).maxAge(3600);
    }

    /**
     * 允许静态资源 *.html 直接访问
     */
    @Override
    public void configurePathMatch(PathMatchConfigurer configurer) {
        super.configurePathMatch(configurer);
        configurer.setUseSuffixPatternMatch(false);
    }

    /**
     * 参数转换，前端参数转成后端实体
     */
    @Bean
    public ConfigurableWebBindingInitializer customConfigurableWebBindingInitializer() {
        ConfigurableWebBindingInitializer initializer = new ConfigurableWebBindingInitializer();

        // 使用 FactoryBean 方式，这样的话就能吧Spring默认的也加进来，自定义的将追加到最后面
        FormattingConversionServiceFactoryBean conversionServiceFactoryBean = new FormattingConversionServiceFactoryBean();

        Set<Converter> converters = new HashSet<>();
        converters.add(new StringToDateConverter());
        converters.add(new StringToConverterVOConverter());
        // 这里可以定义别的， 比如你要将JSON字符串转成某个实体也是可以的
        conversionServiceFactoryBean.setConverters(converters);

        conversionServiceFactoryBean.afterPropertiesSet();
        ConversionService conversionService = conversionServiceFactoryBean.getObject();

        initializer.setConversionService(conversionService);

        return initializer;
    }

    /**
     * 自定义 HttpMessageConverter
     * https://docs.spring.io/spring-boot/docs/1.5.8.RELEASE/reference/htmlsingle/#HttpMessageConverters
     *
     * @return
     */
    @Bean
    public HttpMessageConverters customConverters() {
        HttpMessageConverter<byte[]> byteArrayMessageConverter = new ByteArrayHttpMessageConverter();
        CustomMappingJackson2HttpMessageConverter objectHttpMessageConverter = new CustomMappingJackson2HttpMessageConverter();

        objectHttpMessageConverter.setDefaultCharset(Charset.forName("UTF-8"));
        objectHttpMessageConverter.setSupportedMediaTypes(Arrays.asList(
                MediaType.APPLICATION_JSON,
                MediaType.APPLICATION_JSON_UTF8
        ));

        ObjectMapper objectMapper = new ObjectMapper();
        objectMapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));
        // 序列化时，include规则为：不包含为空字符串，空集合，空数组或null的属性
        objectMapper.setSerializationInclusion(JsonInclude.Include.NON_EMPTY);
        objectMapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
        objectHttpMessageConverter.setObjectMapper(objectMapper);

        Jackson2ObjectMapperBuilder builder = Jackson2ObjectMapperBuilder.xml();
        builder.indentOutput(true);

        MappingJackson2XmlHttpMessageConverter xmlObjectHttpMessageConverter = new MappingJackson2XmlHttpMessageConverter(builder.build());

        return new HttpMessageConverters(byteArrayMessageConverter, objectHttpMessageConverter, xmlObjectHttpMessageConverter);
    }
}
